#include "daomanager.h"
#include "databasemanager.h"
#include "specificsearch.h"
#include <QDebug>
#include <QDateTime>
#include <math.h>

DaoManager::DaoManager()
{
    qDebug() << __PRETTY_FUNCTION__;

    // Preparing the database to connections
    DatabaseManager *dbManager = new DatabaseManager();
    dbManager->openDB();

    m_typeDate = 1;
    m_typeMoney = -1;
    m_semaphorMoney = 0;
    m_currentSelectedDate = QDate::currentDate();

    // Colors related to the Category Chart.
    m_colorList << QColor(255,221,0) << QColor(243,132,0) << QColor(166,14,14) << QColor(2,58,101) << QColor(0,173,239);
    m_colorNameList << QString("#FFDD00") << QString("#F38400") << QString("#A60E0E") << QString("#053A65") << QString("#00ADEF");
}

QList<QObject*> convert2ObjList(QList<MoneyCategory*> catList)
{
    QList<QObject*> objList;
    foreach(MoneyCategory* cat, catList)
        objList.append(cat);
    return objList;
}

QList<QObject*> convert2ObjList(QList<Money*> moneyList)
{
    QList<QObject*> objList;
    foreach(Money* money, moneyList)
        objList.append(money);
    return objList;
}

QList<QObject*> convert2ObjList(QList<MoneyGoal*> goalList)
{
    QList<QObject*> objList;
    foreach(MoneyGoal* goal, goalList)
        objList.append(goal);
    return objList;
}

bool DaoManager::login(QString username, QString password)
{
    qDebug() << __PRETTY_FUNCTION__;
    createStandardUser();
    m_user = new MoneyUser(username, password, "");
    if (userLogin(m_user)) {
        m_user = getUser(m_user);
        m_spSearch = new SpecificSearch();
        updatePeriod();
        updateDatePeriodList();
        return true;
    } else return false;
}

bool DaoManager::createUser(QString username, QString password)
{
    qDebug() << __PRETTY_FUNCTION__;
    m_user = new MoneyUser(username, password, "");
    if (registerUser(m_user)) {
        m_user = getUser(m_user);
        m_spSearch = new SpecificSearch();
        updatePeriod();
        updateDatePeriodList();

        return true;
    } else return false;

    return false;
}

/************************ CATEGORIES ******************************/

QList<QObject*> DaoManager::getAllCategories()
{
    qDebug() << __PRETTY_FUNCTION__;
    // Just use the function provided by categorydao
    if (m_user) {
        m_listCategory =  getAllMoneyCategory(m_user->getId());
        updateTotalByCategory();
        updateCategoryColors();
        return convert2ObjList(m_listCategory);
    }
    else return QList<QObject*>();
}


QList<QObject*> DaoManager::addCategory(QString category)
{
    qDebug() << __PRETTY_FUNCTION__ << category;
    MoneyCategory* newCat = new MoneyCategory(-1, category, QDateTime::currentDateTime().toString(), true);
    registerMoneyCategory(newCat, m_user->getId());

    return convert2ObjList(m_listCategory);
}

QList<QObject*> DaoManager::updateCategory(QString name, int index)
{
    qDebug() << __PRETTY_FUNCTION__ << name << index;
    MoneyCategory *cat = m_listCategory.at(index);
    MoneyCategory *catMoney = getCategory(cat, m_user->getId());
    catMoney->setName(name);
    updateMoneyCategory(catMoney);

    return convert2ObjList(m_listCategory);
}

QList<QObject*> DaoManager::removeCategory(int index)
{
    qDebug() << __PRETTY_FUNCTION__;

    MoneyCategory* notWantedCat = m_listCategory.at(index);
    MoneyCategory* cat2BeDeleted = getCategory(notWantedCat, m_user->getId());

    deleteMoneyCategory(cat2BeDeleted);

    return convert2ObjList(m_listCategory);
}

QString DaoManager::today()
{
    qDebug() << __PRETTY_FUNCTION__;
    return QDate::currentDate().toString("dd/MM/yy");
}

QString DaoManager::getCurrentDateString(int typeDate, SpecificSearch *spSearch)
{
    if (typeDate == 0)
        return m_currentSelectedDate.toString("dd/MM/yyyy");
    else if (typeDate == 1)
        return m_currentSelectedDate.toString("MMMM, yyyy");
    else if (typeDate == 2)
        return m_currentSelectedDate.toString("yyyy");
    else if (spSearch)
        return spSearch->dateSince() + " - " + spSearch->dateUntil();
    return "";
}

QString DaoManager::currentDate()
{
    qDebug() << __PRETTY_FUNCTION__;

    return getCurrentDateString(m_typeDate, m_spSearch);
}

QString DaoManager::nextDate()
{
    qDebug() << __PRETTY_FUNCTION__;

    if (m_typeDate == 0)
        m_currentSelectedDate = m_currentSelectedDate.addDays(1);
    else if (m_typeDate == 1)
        m_currentSelectedDate = m_currentSelectedDate.addMonths(1);
    else if (m_typeDate == 2)
        m_currentSelectedDate = m_currentSelectedDate.addYears(1);
    else {
        int days = m_spSearch->getSinceDt().daysTo(m_spSearch->getUntilDt());
        m_spSearch->setSinceDt(m_spSearch->getSinceDt().addDays(days));
        m_spSearch->setUntilDt(m_spSearch->getUntilDt().addDays(days));
    }

    updatePeriod();
    updateDatePeriodList();

    return currentDate();
}

QString DaoManager::previousDate()
{
    qDebug() << __PRETTY_FUNCTION__;

    if (m_typeDate == 0)
        m_currentSelectedDate = m_currentSelectedDate.addDays(-1);
    else if (m_typeDate == 1)
        m_currentSelectedDate = m_currentSelectedDate.addMonths(-1);
    else if (m_typeDate == 2)
        m_currentSelectedDate = m_currentSelectedDate.addYears(-1);

    updatePeriod();
    updateDatePeriodList();

    return currentDate();
}

/************************ MONEY ******************************/
QList<QObject*> DaoManager::getAllMoneyRegister()
{
    qDebug() << __PRETTY_FUNCTION__ << m_typeMoney;

    if (m_semaphorMoney == 0) {
        m_semaphorMoney = 1;

        Money::money_types tt = Money::type_none;
        if ( m_typeMoney == 0)
            tt = Money::type_in;
        else if (m_typeMoney == 1)
            tt = Money::type_out;
        m_listCurrentSeenMoney = getAllMoney(m_user->getId(),m_listCategory, m_spSearch, tt);

        m_semaphorMoney = 0;
    }

    return convert2ObjList(m_listCurrentSeenMoney);
}

QList<QObject*> DaoManager::addMoney(int type, int indexCategory, QString description, double amount, QString date)
{
    qDebug() << __PRETTY_FUNCTION__ << type << indexCategory << description << amount << date;

    Money *newMoney = new Money();
    newMoney->setMoneyType(type);
    if (indexCategory >= 0 && indexCategory < m_listCategory.length())
        newMoney->setCategory(m_listCategory.at(indexCategory));
    newMoney->setDescription(description);
    newMoney->setAmount(amount);
    newMoney->setMoneyDate(date);
    registerMoney(newMoney, m_user->getId());

    return convert2ObjList(m_listCurrentSeenMoney);
}

QList<QObject*> DaoManager::updateMoneyRegister(int type, int indexCategory, QString description, double amount, QString date)
{
    qDebug() << __PRETTY_FUNCTION__ << description;
    Money *money;
    money = getMoney(m_money2BeEdited, m_listCategory, m_user->getId());
    if (money == 0)
        return QList<QObject*>();
    money->setMoneyType(type);
    if (indexCategory >= 0 && indexCategory < m_listCategory.length())
        money->setCategory(m_listCategory.at(indexCategory));
    money->setDescription(description);
    money->setAmount(amount);
    money->setMoneyDate(date);
    updateMoney(money);

    return convert2ObjList(m_listCurrentSeenMoney);
}

QList<QObject*> DaoManager::removeMoneyRegister(int index)
{
    qDebug() << __PRETTY_FUNCTION__;

    Money *money2BeDeleted = m_listCurrentSeenMoney.at(index);
    money2BeDeleted = getMoney(money2BeDeleted, m_listCategory, m_user->getId());

    deleteMoney(money2BeDeleted);

    return convert2ObjList(m_listCurrentSeenMoney);
}

QList<QObject*> DaoManager::getAllTypeMoney()
{
    qDebug() << __PRETTY_FUNCTION__;

    QStringList typeList;
    typeList << "Todos" << "Entrada" << "Saida";
    QList<MoneyCategory*> listTypes;
    for (int i = 0; i < typeList.length(); i++) {
        listTypes.append(new MoneyCategory(i, typeList.at(i), "", false));
    }
    return convert2ObjList(listTypes);
}

void DaoManager::setMoney2BeEdited(int index)
{
    qDebug() << __PRETTY_FUNCTION__;
    m_money2BeEdited = m_listCurrentSeenMoney.at(index);
}

Money* DaoManager::money2BeEdited()
{
    qDebug() << __PRETTY_FUNCTION__;
    return m_money2BeEdited;
}


float DaoManager::totalCashFlow()
{

    float total = 0;
    foreach(Money* money, m_listCurrentSeenMoney)
        total = total + (2 * (1 - money->moneyType()) - 1) * money->amount();

    qDebug() << __PRETTY_FUNCTION__ << total;

    return total;
}


float DaoManager::totalIncomes()
{
    float total = 0;
    foreach(Money* money, m_listCurrentSeenMoney)
        if (money->getTypeMoney() == Money::type_in)
            total = total + money->amount();

    qDebug() << __PRETTY_FUNCTION__ << total;

    return total;
}


float DaoManager::totalOutcomes()
{
    float total = 0;
    foreach(Money* money, m_listCurrentSeenMoney)
        if (money->getTypeMoney() == Money::type_out)
            total = total + money->amount();

    qDebug() << __PRETTY_FUNCTION__ << total;

    return total;
}

void DaoManager::updateTotalByCategory()
{
   //qDebug() << __PRETTY_FUNCTION__;

    float total = 0;
    foreach (MoneyCategory* cat, m_listCategory) {
        total = total + cat->totalExpenses();
    }

    foreach (MoneyCategory* cat, m_listCategory) {
       if (total != 0)
        cat->setPercentage(floor((cat->totalExpenses()/total)*100));
       else  cat->setPercentage(0);
    }

}

void DaoManager::setMoneyType(int typeMoney)
{
    qDebug() << __PRETTY_FUNCTION__ << typeMoney;
    if (typeMoney != m_typeMoney) {
        m_typeMoney = typeMoney;
    }
}

void DaoManager::setTypeDate(int typeDate)
{
    qDebug() << __PRETTY_FUNCTION__ << typeDate;
    if (typeDate != m_typeDate) {
        m_typeDate = typeDate;
        updatePeriod();
    } else {
        m_typeDate = typeDate;
    }
}


void DaoManager::setSpSearch(SpecificSearch *sp)
{
    qDebug() << __PRETTY_FUNCTION__ << sp->category();
//    if (sp->category())
//        qDebug() << __PRETTY_FUNCTION__ << sp->category()->name();
    m_spSearch = sp;
    if (m_spSearch) {
        updateDatePeriodList();
    }
}

SpecificSearch* DaoManager::spSearch()
{
    qDebug() << __PRETTY_FUNCTION__;
    return m_spSearch;
}

void DaoManager::updatePeriod()
{
    qDebug() << __PRETTY_FUNCTION__;
    m_spSearch = updateSpSearch(m_typeDate, m_spSearch);
}


SpecificSearch* DaoManager::updateSpSearch(int typeDate, SpecificSearch *spSearch)
{
    qDebug() << __PRETTY_FUNCTION__;

    if (!spSearch)
        spSearch = new SpecificSearch();
    if (typeDate == 0) {
        spSearch->setActiveSinceDt(true);
        spSearch->setActiveUntilDt(true);

        spSearch->setSinceDt(m_currentSelectedDate);
        spSearch->setUntilDt(m_currentSelectedDate);
    } else if (typeDate == 1) {

        spSearch->setActiveSinceDt(true);
        spSearch->setActiveUntilDt(true);

        QDate beginDate, endDate;
        beginDate.setDate(m_currentSelectedDate.year(), m_currentSelectedDate.month(), 1);
        endDate.setDate(m_currentSelectedDate.year(), m_currentSelectedDate.month(), m_currentSelectedDate.daysInMonth());

        spSearch->setSinceDt(beginDate);
        spSearch->setUntilDt(endDate);
    } else if (typeDate == 2) {

        spSearch->setActiveSinceDt(true);
        spSearch->setActiveUntilDt(true);

        QDate beginDate, endDate;
        beginDate.setDate(m_currentSelectedDate.year(), 1, 1);
        endDate.setDate(m_currentSelectedDate.year(), 12, 31);

        spSearch->setSinceDt(beginDate);
        spSearch->setUntilDt(endDate);
    }

    return spSearch;
}


QList<QObject*> DaoManager::getAllDatePeriods()
{
    qDebug() << __PRETTY_FUNCTION__;

    return convert2ObjList(m_listDatePeriods);
}

void DaoManager::updateDatePeriodList()
{
    qDebug() << __PRETTY_FUNCTION__;

    QStringList typeList;

    SpecificSearch* sp = 0;

    for (int typeDate = 0; typeDate <= 3; typeDate++) {
        if (typeDate != 3)
            sp = updateSpSearch(typeDate, sp);
        else {
            sp = new SpecificSearch;
            sp->setDateSince(m_spSearch->dateSince());
            sp->setDateUntil(m_spSearch->dateUntil());
        }
        typeList << getCurrentDateString(typeDate, sp);
    }

    m_listDatePeriods.clear();
    for (int i = 0; i < typeList.length(); i++) {
        m_listDatePeriods.append(new MoneyCategory(i, typeList.at(i), "", false));
    }
}

void DaoManager::createCsvFile()
{
    qDebug() << __PRETTY_FUNCTION__;
     QFile file("money-manager.csv");
     if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
         return;

     QTextStream out(&file);

     //Fields Name
     out << "\"Tipo Registro\"," << "\"Categoria\"," <<  "\"Descricao\"," << "\"Valor\"," <<  "\"Data\"," << "\n";

     foreach (Money* money, m_listCurrentSeenMoney)
         out << "\""  << (money->moneyType() == 0? "Entrada": "Saida") << "\","
             << "\""  <<  (money->category() != 0 ? money->category()->name() : " ") << "\","
             << "\""  << money->description() << "\","
             << "\""  << money->amount() << "\","
             << "\""  << money->moneyDate() << "\"," << "\n";


}

/************************ GOALS ******************************/

QList<QObject*> DaoManager::getAllGoals()
{
    qDebug() << __PRETTY_FUNCTION__;
    m_listGoal = getAllMoneyGoal(m_user->getId());
    return convert2ObjList(m_listGoal);
}

QList<QObject*> DaoManager::addGoal(int type, float target, QString initialDate, QString finalDate, QString description)
{
    qDebug() << __PRETTY_FUNCTION__ << type << target << initialDate << finalDate << description;
    MoneyGoal *newGoal = new MoneyGoal();
    newGoal->setGoalType(type);
    newGoal->setTarget(target);
    newGoal->setInitialDate(initialDate);
    newGoal->setFinalDate(finalDate);
    newGoal->setDescription(description);
    registerMoneyGoal(newGoal, m_user->getId());

    return convert2ObjList(m_listGoal);
}


QList<QObject*> DaoManager::removeGoal(int index)
{
    qDebug() << __PRETTY_FUNCTION__ << index;
    MoneyGoal *goal = m_listGoal.at(index);
    goal = getGoal(goal, m_user->getId());
    deleteMoneyGoal(goal);

    return convert2ObjList(m_listGoal);
}

QList<QObject*> DaoManager::updateGoal(int type, float target, QString initialDate, QString finalDate, QString description, int index)
{
    qDebug() << __PRETTY_FUNCTION__ << type << target << initialDate << finalDate << description;
    MoneyGoal *goal = m_listGoal.at(index);
    goal = getGoal(goal, m_user->getId());
    if (goal) {
        goal->setGoalType(type);
        goal->setTarget(target);
        goal->setInitialDate(initialDate);
        goal->setFinalDate(finalDate);
        goal->setDescription(description);
        updateMoneyGoal(goal);
    }
    return convert2ObjList(m_listGoal);
}

QList<QObject*> DaoManager::getAllTypeGoal()
{
    qDebug() << __PRETTY_FUNCTION__;

    QStringList typeList;
    typeList << "Total" << "Entrada" << "Saida";
    QList<MoneyCategory*> listTypes;
    for (int i = 0; i < typeList.length(); i++) {
        listTypes.append(new MoneyCategory(i, typeList.at(i), "", false));
    }
    return convert2ObjList(listTypes);
}
/*************************************************************/

void DaoManager::updateCategoryColors()
{
    qDebug() << __PRETTY_FUNCTION__;

    for(int i = 0; i < m_listCategory.length() && i < m_colorList.length() && i < m_colorNameList.length(); i++) {
        MoneyCategory* cat = m_listCategory.at(i);
        cat->setColor(m_colorNameList.at(i));
        cat->setColorRgb(m_colorList.at(i));
        m_listCategory.replace(i, cat);
    }
}
